/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simplemetrosystem.control;

import java.awt.Color;
import java.util.Observable;
import simplemetrosystem.model.Command.Command;
import simplemetrosystem.model.Command.CommandStack;
import simplemetrosystem.model.Command.EditCommand.AddEdgeCommand;
import simplemetrosystem.model.Command.EditCommand.AddLineCommand;
import simplemetrosystem.model.Command.EditCommand.AddStationCommand;
import simplemetrosystem.model.Command.EditCommand.AddStringCommand;
import simplemetrosystem.model.Command.EditCommand.EditEdgeCommand;
import simplemetrosystem.model.Command.EditCommand.EditLineCommand;
import simplemetrosystem.model.Command.EditCommand.EditStationCommand;
import simplemetrosystem.model.Command.EditCommand.EditStringCommand;
import simplemetrosystem.model.Command.EditCommand.RemoveLineCommand;
import simplemetrosystem.model.Command.EditCommand.RemoveEdgeCommand;
import simplemetrosystem.model.Command.EditCommand.RemoveStationCommand;
import simplemetrosystem.model.Command.EditCommand.RemoveStringCommand;
import simplemetrosystem.model.Element.MetroEdge;
import simplemetrosystem.model.Element.MetroLine;
import simplemetrosystem.model.Element.MetroStation;
import simplemetrosystem.model.Element.MetroString;

/**
 *
 * @author Eric Qian
 */
public class EditCommandManager extends Observable {

    /**
     * 
     * @return
     */
    public static EditCommandManager getInstance() {
        return editCommandManager;
    }

    /**
     * 
     * @param stepSize
     * @return
     */
    public static EditCommandManager newInstance(int stepSize) {
        editCommandManager = new EditCommandManager(stepSize);
        return editCommandManager;
    }

    /**
     * 
     * @param stepSize
     */
    private EditCommandManager(int stepSize) {
        this.stepSize = stepSize;
        undoStack = new CommandStack(stepSize);
        redoStack = new CommandStack(stepSize);
        isClear = true;

        if (ElementManager.getInstance().getPath() == null) {
            isNew = true;
        } else {
            isNew = false;
        }
    }

    /**
     * 
     */
    private void EditChanged() {
        setNew();
        setClear(false);
        setChanged();
        notifyObservers();
    }

    /**
     * 
     */
    public void undo() {
        Command aCommand = undoStack.pop();
        aCommand.undo();
        redoStack.push(aCommand);
        EditChanged();
    }

    /**
     * 
     */
    public void redo() {
        Command aCommand = redoStack.pop();
        aCommand.execute();
        undoStack.push(aCommand);
        EditChanged();
    }

    /**
     * 
     * @return
     */
    public boolean undoEnabled() {
        return !undoStack.empty();
    }

    /**
     * 
     * @return
     */
    public boolean redoEnabled() {
        return !redoStack.empty();
    }

    /**
     * 
     * @return
     */
    public boolean isNew() {
        return isNew;
    }

    /**
     * 
     */
    public void setNew() {
        isNew = false;
    }

    /**
     * 
     * @return
     */
    public boolean isClear() {
        return isClear;
    }

    /**
     * 
     * @param status 
     */
    public void setClear(boolean status) {
        isClear = status;
    }

    /**
     * 
     * @param name
     */
    public void addLine(String name) {
        Command aCommand = new AddLineCommand(name);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    public void addStation(String name, int logX, int logY) {
        Command aCommand = new AddStationCommand(name, logX, logY);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param stA
     * @param stB
     * @param lineName
     */
    public void addEdge(String stA, String stB, String lineName) {
        Command aCommand = new AddEdgeCommand(stA, stB, lineName);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param text
     * @param element
     * @param logX
     * @param logY
     */
    public void addString(String text, String element, int logX, int logY) {
        Command aCommand = new AddStringCommand(text, element, logX, logY);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param line
     */
    public void removeLine(MetroLine line) {
        Command aCommand = new RemoveLineCommand(line);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param station
     */
    public void removeStation(MetroStation station) {
        Command aCommand = new RemoveStationCommand(station);
        aCommand.execute();
        undoStack.push(aCommand);
        EditChanged();
    }

    /**
     * 
     * @param edge
     */
    public void removeEdge(MetroEdge edge) {
        Command aCommand = new RemoveEdgeCommand(edge);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param string
     */
    public void removeString(MetroString string) {
        Command aCommand = new RemoveStringCommand(string);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param line
     * @param name
     * @param cName
     * @param status
     * @param color
     */
    public void EditLine(MetroLine line, String name, String cName, String status, Color color) {
        Command aCommand = new EditLineCommand(line, name, cName, status, color);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param satation
     * @param name
     * @param cName
     * @param logX
     * @param logY
     * @param natX
     * @param natY
     */
    public void EditStation(MetroStation satation, String name, String cName,
            int logX, int logY, double natX, double natY) {
        Command aCommand = new EditStationCommand(
                satation, name, cName, logX, logY, natX, natY);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param edge
     * @param line
     * @param serialNumber
     * @param distance
     * @param time
     */
    public void EditEdge(MetroEdge edge, MetroLine line, int serialNumber, double distance, double time) {
        Command aCommand = new EditEdgeCommand(edge, line, serialNumber, distance, time);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }

    /**
     * 
     * @param string
     * @param text
     * @param logX
     * @param logY
     */
    public void EditString(MetroString string, String text, int logX, int logY) {
        Command aCommand = new EditStringCommand(string, text, logX, logY);
        aCommand.execute();
        undoStack.push(aCommand);

        EditChanged();
    }
    private static EditCommandManager editCommandManager;
    private CommandStack undoStack;
    private CommandStack redoStack;
    private int stepSize;
    private boolean isNew;
    private boolean isClear;
}
